import operator
import pymysql as db
from pprint import pprint
from datetime import datetime
from datetime import timedelta

conn = db.connect(
		host='127.0.0.1', port=3306, user='root', passwd='wlywly', db='mit_reality_full')

TEST_DATE = datetime(2004, 11, 8, 0, 0, 0)

def execute_query_fetch_all(query):
    cur = conn.cursor()
    cur.execute(query) 
    results = cur.fetchall() 
    cur.close()
    return results

DATA_USERS_ID = [29,39,79,37,47,63,91,15,57,80,75,69,94,78,43,95,72,73,16,85,88,60,35,54,50,66,17,18,20,28]
DATA_USER_DEVICES_ID = [15,16,17,49,18,40,20,29,30,36,38,41,93,46,51,54,58,61,64,67,70,73,76,77,79,83,84,85,90,94,97,100,101]

NON_DATA_USERS_ID = [1,2,3,4,6,7,8,10,11,12,14,19,22,23,24,26,32,33,36,38,40,42,46,49,51,59,61,65,70,74,76,77,81,83,84,86,89,90,92,96,97]
NON_DATA_USER_DEVICES_ID = [1,2,3,4,6,7,8,10,11,12,14,19,22,23,24,25,27,33,34,37,39,42,43,45,50,53,55,63,65,69,74,78,80,81,82,86,88,89,91,95,96,98,102,103]

ALL_USERS_ID = DATA_USERS_ID + NON_DATA_USERS_ID
ALL_USER_DEVICES_ID = DATA_USER_DEVICES_ID + NON_DATA_USER_DEVICES_ID

FIXED_DEVICES_ID = [120, 438]


class CriticalEvent:
	def __init__(self, user_id, event_time, event_type):
		self.user = user_id
		self.time = event_time
		self.type = event_type #0:voice call, 1:meet device, 2:meet other user
		self.user2 = "None"

	def description(self):
		return "{}\t{}\t{}\t{}".format(self.time, self.type, self.user, self.user2)

def is_data_user(user):
	if int(user) in DATA_USERS_ID:
		return True
	else:
		return False

user_statuses = {}
server_results = []

def init_user_statues():
	for user in ALL_USERS_ID:
		if not is_data_user(user):
			user_statuses[user] = [user,]
		else:
			user_statuses[user] = [-1, ]

def status(user_id):
	return user_statuses[int(user_id)]

def findAllCriticalEvents(date_query):
	meet_device_events = findAllFixedDeviceMeetings(date_query)
	meet_user_events = findAllUserMeetings(date_query)
	all_events = meet_device_events + meet_user_events
	#sort according to event happening time
	all_events.sort(key=operator.attrgetter('time'))
	with open("all_events_{}.txt".format(date_query.day), "w") as outputfile:
		for event in all_events:
			outputfile.write("{} {} {} {}\n".format(event.time, event.type, event.user, event.user2))
	return all_events

def findAllFixedDeviceMeetings(date_query):
	#useful for all users
	starttime = date_query
	endtime = date_query + timedelta(days=1)
	all_users_id = ','.join(str(x) for x in ALL_USERS_ID)
	fixed_devices_id = ','.join(str(x) for x in FIXED_DEVICES_ID)
	query = """
			select person_oid, starttime from devicespan
			where person_oid in ({all_users})
			and starttime between '{start}' and '{end}'
			and device_oid in ({fixed_devices})
			""".format(all_users=all_users_id, start=starttime, end=endtime, fixed_devices=fixed_devices_id)
	results = execute_query_fetch_all(query)
	events = []
	for result in results:
		new_device_meeting = CriticalEvent(result[0], result[1], 1)
		events.append(new_device_meeting)
	return events

def findAllUserMeetings(date_query):
	#useful for all users
	starttime = date_query
	endtime = date_query + timedelta(days=1)
	all_users_id = ','.join(str(x) for x in NON_DATA_USERS_ID)
	user_devices_id = ','.join(str(x) for x in ALL_USER_DEVICES_ID)
	query = """
			select person_oid, starttime, device_oid from devicespan
			where person_oid in ({all_users})
			and starttime between '{start}' and '{end}'
			and device_oid in ({user_devices})
			""".format(all_users=all_users_id, start=starttime, end=endtime, user_devices=user_devices_id)
	results = execute_query_fetch_all(query)
	events = []
	for result in results:
		new_user_meeting = CriticalEvent(result[0], result[1], 2)
		connect_user = device_to_user(result[2])
		new_user_meeting.user2 = connect_user
		events.append(new_user_meeting)
	return events

device2user = {}
def init_device_to_user_dict():
	with open('device_id2user_id.txt','r') as inputfile:
		for line in inputfile.readlines():
			word = line.split()
			device2user[word[0]]=word[1]

def device_to_user(device_id):
	return device2user[str(device_id)]


def flooding(date_query):
	critical_events = findAllCriticalEvents(date_query)
	for e in critical_events:
		user1 = int(e.user)
		if e.type == 1:
			server_results = set(server_results.append(user_statuses[user1])) #meet device
		if e.type == 2:
			user2 = int(e.user2)
			user_statuses[user2] = set(user_statuses[user2].append(user_statuses[user1])) #flooding to all the users

	for user in DATA_USERS_ID:
		server_results = set(server_results.append(user_statuses[user]))

	print len(server_results)

if __name__ == '__main__':
	
	init_device_to_user_dict()

	for i in range(7*2):
		init_user_statues()
		server_results = []
		flooding(TEST_DATE+timedelta(days=i))

	conn.close()